/**
    MVP Tree data structure using graph database for I/O storage
    Copyright (C) 2014  David G. Starkweather

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.

    David Starkweather starkd88@gmail.com
**/

package org.phash.mvptree;

import java.util.Collection;
import java.util.Vector;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.Relationship;
import org.neo4j.graphdb.Direction;
import org.neo4j.graphdb.Transaction;

class MVPLeaf extends MVPNode {
    final String DP = "DP";

    MVPLeaf(Node node){
	super(node);
	int ntype = NodeType.LEAF_NODE.ordinal();;
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    node.setProperty(NODETYPE, ntype);
	    tx.success();
	} finally { 
	    tx.finish();
	}
    }

    int getPointCount(){
	Node node = getNode();
	Transaction tx = node.getGraphDatabase().beginTx();
	int retval = 0;
	try {
	    Iterable<Relationship> rels = node.getRelationships(MVPRelationshipTypes.HAS, Direction.OUTGOING);
	    int count = 0;
	    for (Relationship rel : rels){
		count++;
	    }
	    tx.success();
	    retval = count;
	} finally {
	    tx.finish();
	}
	return retval;
    }

    void addDatapoint(Datapoint point){
	Node node = getNode();
	int ord = getPointCount();
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    Relationship rel = node.createRelationshipTo(point.getNode(), MVPRelationshipTypes.HAS);
	    rel.setProperty(DP, ord);
	    tx.success();
	} finally {
	    tx.finish();
	}
    }

    Datapoint getDatapoint(int n, NodeFactory nodeFactory){
	Node node = getNode();
	Datapoint point = null;
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    Iterable<Relationship> rels = getNode().getRelationships(MVPRelationshipTypes.HAS, Direction.OUTGOING);
	    for (Relationship rel : rels){
		if ((int)rel.getProperty(DP) == n){
		    Node endNode = rel.getEndNode();
		    if (endNode != null){
			point = nodeFactory.createDatapoint(endNode);
		    }
		    break;
		}
	    }
	    tx.success();
	} finally {
	    tx.finish();
	}
	return point;
    }

    void addDatapoints(Collection<Datapoint> points){
	for (Datapoint pnt : points){
	    addDatapoint(pnt);
	}
    }

    Iterable<Datapoint> getAllPoints(NodeFactory nodeFactory){
	Node node = getNode();
	Vector<Datapoint> points = new Vector<Datapoint>();
	Transaction tx = node.getGraphDatabase().beginTx();
	try {
	    Iterable<Relationship> rels = node.getRelationships(MVPRelationshipTypes.HAS, Direction.OUTGOING);
	    for (Relationship rel : rels){
		Node endnode = rel.getEndNode(); 
		Datapoint point = nodeFactory.createDatapoint(endnode);
		points.add(point);
	    }
	    tx.success();
	} finally { 
	    tx.finish();
	}

	return points;
    }
}
